#! /bin/sh /usr/share/dpatch/dpatch-run
## 80_6719_channel_thread_p1.dpatch by  <root@mythserver.home.rodriguez-vudoyra.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.

@DPATCH@
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/analogsignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/analogsignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/analogsignalmonitor.cpp	2009-10-14 20:32:59.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/analogsignalmonitor.cpp	2009-12-27 01:22:18.000000000 -0600
@@ -32,6 +32,9 @@
     if (videofd < 0)
         return;
 
+    if (!IsChannelTuned())
+        return;
+
     bool isLocked = false;
     if (usingv4l2)
     {
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelbase.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelbase.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelbase.cpp	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelbase.cpp	2009-12-27 01:37:05.000000000 -0600
@@ -35,25 +35,109 @@
 #define LOC_WARN QString("ChannelBase(%1) Warning: ").arg(GetCardID())
 #define LOC_ERR QString("ChannelBase(%1) Error: ").arg(GetCardID())
 
+/*
+ * Run the channel change thread, and report the status when done
+ */
+void ChannelThread::run(void)
+{
+    bool result = tuner->SetChannelByString(channel);
+    tuner->setStatus(result ?
+                     ChannelBase::changeSuccess : ChannelBase::changeFailed);
+}
+
 ChannelBase::ChannelBase(TVRec *parent)
     :
     pParent(parent), curchannelname(""),
-    currentInputID(-1), commfree(false), cardid(0)
+    currentInputID(-1), commfree(false), cardid(0),
+    abort_change(false)
+ {
+    tuneStatus = changeUnknown;
+    tuneThread.tuner = this;
+ }
+
+ChannelBase::~ChannelBase(void)
+{
+    TeardownAll();
+}
+
+void ChannelBase::TeardownAll(void)
 {
+    if (tuneThread.isRunning())
+    {
+        thread_lock.lock();
+        abort_change = true;
+        tuneCond.wakeAll();
+        thread_lock.unlock();
+        tuneThread.wait();
+    }
 }
 
-ChannelBase::~ChannelBase(void)
+void ChannelBase::SelectChannel(const QString & chan)
+{
+    VERBOSE(VB_CHANNEL, LOC + "SelectChannel " + chan);
+    TeardownAll();
+
+    thread_lock.lock();
+    abort_change = false;
+    tuneStatus = changePending;
+    thread_lock.unlock();
+
+    curchannelname = tuneThread.channel = chan;
+    tuneThread.start();
+}
+
+/*
+ * Returns true of the channel change thread should abort
+ */
+bool ChannelBase::Aborted(void)
+{
+    bool       result;
+
+    thread_lock.lock();
+    result = abort_change;
+    thread_lock.unlock();
+
+    return result;
+}
+
+ChannelBase::Status ChannelBase::GetStatus(void)
+{
+    Status status;
+
+    thread_lock.lock();
+    status = tuneStatus;
+    thread_lock.unlock();
+
+    return status;
+}
+
+ChannelBase::Status ChannelBase::Wait(void)
+{
+    tuneThread.wait();
+    return tuneStatus;
+}
+
+void ChannelBase::setStatus(ChannelBase::Status status)
 {
+    thread_lock.lock();
+    tuneStatus = status;
+    thread_lock.unlock();
 }
 
 bool ChannelBase::Init(QString &inputname, QString &startchannel, bool setchan)
 {
     bool ok;
 
+    VERBOSE(VB_CHANNEL, LOC + QString("Init(%1, %2, %3)")
+            .arg(inputname).arg(startchannel).arg(setchan));
+
     if (!setchan)
         ok = inputname.isEmpty() ? false : IsTunable(inputname, startchannel);
     else if (inputname.isEmpty())
-        ok = SetChannelByString(startchannel);
+    {
+        SelectChannel(startchannel);
+        ok = Wait();
+    }
     else
         ok = SwitchToInput(inputname, startchannel);
 
@@ -124,10 +208,8 @@
             if (chanid && cit != channels.end())
             {
                 if (!setchan)
-                {
                     ok = IsTunable(*it, (mplexid_restriction) ?
                                    (*cit).channum : startchannel);
-                }
                 else
                     ok = SwitchToInput(*it, (*cit).channum);
 
@@ -329,6 +411,7 @@
     return -1;
 }
 
+#if 0 // Not used?
 bool ChannelBase::SwitchToInput(const QString &inputname)
 {
     int input = GetInputByName(inputname);
@@ -340,29 +423,60 @@
                                       "%1 on card\n").arg(inputname));
     return false;
 }
+#endif
+
+bool ChannelBase::SelectInput(const QString &inputname, const QString &chan)
+{
+    int input = GetInputByName(inputname);
+
+    VERBOSE(VB_CHANNEL, LOC + QString("SelectInput(%1, %2) %3")
+            .arg(inputname).arg(chan).arg(input));
+
+    if (input >= 0)
+    {
+        if (!SwitchToInput(input, false))
+            return false;
+        SelectChannel(chan);
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT,
+                QString("ChannelBase: Could not find input: %1 on card when "
+                        "setting channel %2\n").arg(inputname).arg(chan));
+        return false;
+    }
+
+    return true;
+}
 
 bool ChannelBase::SwitchToInput(const QString &inputname, const QString &chan)
 {
     int input = GetInputByName(inputname);
 
-    bool ok = false;
+    VERBOSE(VB_CHANNEL, LOC + QString("SwitchToInput(%1, %2), %3")
+            .arg(inputname).arg(chan).arg(input));
+
     if (input >= 0)
     {
-        ok = SwitchToInput(input, false);
-        if (ok)
-            ok = SetChannelByString(chan);
+        if (!SwitchToInput(input, false))
+            return false;
+        return SetChannelByString(chan);
     }
     else
     {
         VERBOSE(VB_IMPORTANT,
                 QString("ChannelBase: Could not find input: %1 on card when "
                         "setting channel %2\n").arg(inputname).arg(chan));
+        return false;
     }
-    return ok;
+    return true;
 }
 
 bool ChannelBase::SwitchToInput(int newInputNum, bool setstarting)
 {
+    VERBOSE(VB_CHANNEL, LOC + QString("SwitchToInput(%1, %2)")
+            .arg(newInputNum).arg(setstarting));
+
     InputMap::const_iterator it = inputs.find(newInputNum);
     if (it == inputs.end() || (*it)->startChanNum.isEmpty())
         return false;
@@ -374,7 +488,7 @@
     // input switching code would go here
 
     if (setstarting)
-        return SetChannelByString((*it)->startChanNum);
+        SelectChannel((*it)->startChanNum);
 
     return true;
 }
@@ -485,8 +599,7 @@
     return is_busy;
 }
 
-bool ChannelBase::IsInputAvailable(
-    int inputid, uint &mplexid_restriction) const
+bool ChannelBase::IsInputAvailable(int inputid, uint &mplexid_restriction) const
 {
     if (inputid < 0)
         return false;
@@ -652,25 +765,37 @@
     else
     {   // child contains the pid of the new process
-        int status = 0, pid = 0;
+        QMutex      lock;
+        int         status = 0, pid = 0;
+
         VERBOSE(VB_CHANNEL, "Waiting for External Tuning program to exit");
 
         bool timed_out = false;
         uint timeout = 30; // how long to wait in seconds
         time_t start_time = time(0);
-        while (-1 != pid && !timed_out)
+        while (-1 != pid && !timed_out && !Aborted())
         {
-            sleep(1);
+            lock.lock();
+            tuneCond.wait(&lock, 500);  // sleep up to 0.5 seconds
             pid = waitpid(child, &status, WUNTRACED|WNOHANG);
             VERBOSE(VB_IMPORTANT, QString("ret_pid(%1) child(%2) status(0x%3)")
                     .arg(pid).arg(child).arg(status,0,16));
             if (pid==child)
+            {
+                lock.unlock();
                 break;
+            }
             else if (time(0) > (time_t)(start_time + timeout))
                 timed_out = true;
+            lock.unlock();
         }
-        if (timed_out)
+
+        if (timed_out || Aborted())
         {
-            VERBOSE(VB_IMPORTANT, "External Tuning program timed out, killing");
+            if (Aborted())
+                VERBOSE(VB_IMPORTANT, "Aborting External Tuning program");
+            else
+                VERBOSE(VB_IMPORTANT, "External Tuning program timed out, "
+                        "killing");
             kill(child, SIGTERM);
             usleep(500);
             kill(child, SIGKILL);
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelbase.h mythtv-0.22.0-fixes23003/libs/libmythtv/channelbase.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelbase.h	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelbase.h	2009-12-27 01:40:56.000000000 -0600
@@ -6,6 +6,10 @@
 // Qt headers
 #include <qmap.h>
 #include <qstringlist.h>
+#include <qwaitcondition.h>
+#include <qmutex.h>
+#include <qthread.h>
+
 
 // MythTV headers
 #include "channelutil.h"
@@ -13,6 +17,19 @@
 #include "tv.h"
 
 class TVRec;
+class ChannelBase;
+
+/*
+ * Thread to run tunning process in
+ */
+class ChannelThread : public QThread
+{
+  public:
+    virtual void run(void);
+
+    QString      channel;
+    ChannelBase *tuner;
+};
 
 /** \class ChannelBase
  *  \brief Abstract class providing a generic interface to tuning hardware.
@@ -24,19 +41,28 @@
 
 class ChannelBase
 {
- public:
+    friend class ChannelThread;
+
+  public:
+    enum Status { changeUnknown = 'U', changePending = 'P',
+                  changeFailed = 'F', changeSuccess = 'S' };
+
     ChannelBase(TVRec *parent);
-    virtual ~ChannelBase();
+    virtual ~ChannelBase(void);
 
     virtual bool Init(QString &inputname, QString &startchannel, bool setchan);
     virtual bool IsTunable(const QString &input, const QString &channum) const;
 
+    virtual void SelectChannel(const QString & chan);
+
+    Status GetStatus(void);
+    Status Wait(void);
+
     // Methods that must be implemented.
     /// \brief Opens the channel changing hardware for use.
     virtual bool Open(void) = 0;
     /// \brief Closes the channel changing hardware to use.
     virtual void Close(void) = 0;
-    virtual bool SetChannelByString(const QString &chan) = 0;
     /// \brief Reports whether channel is already open
     virtual bool IsOpen(void) const = 0;
 
@@ -83,8 +109,9 @@
                           const QString &newChanNum);
 
     // Input toggling convenience methods
-    virtual bool SwitchToInput(const QString &input);
-    virtual bool SwitchToInput(const QString &input, const QString &chan);
+
+//    virtual bool SwitchToInput(const QString &input); // not used?
+    virtual bool SelectInput(const QString &input, const QString &chan);
 
     virtual bool InitializeInputs(void);
 
@@ -109,8 +136,11 @@
 
     virtual int GetCardID(void) const;
   protected:
+    virtual bool SetChannelByString(const QString &chan) = 0;
+
     /// \brief Switches to another input on hardware, 
     ///        and sets the channel is setstarting is true.
+    virtual bool SwitchToInput(const QString &input, const QString &chan);
     virtual bool SwitchToInput(int inputNum, bool setstarting);
     virtual bool IsInputAvailable(
         int inputNum, uint &mplexid_restriction) const;
@@ -119,6 +149,10 @@
     static void StoreInputChannels(const InputMap&);
     static void StoreDefaultInput(uint cardid, const QString &input);
 
+    bool Aborted();
+    void setStatus(Status status);
+    void TeardownAll(void);
+
     TVRec   *pParent;
     QString  curchannelname;
     int      currentInputID;
@@ -126,6 +160,14 @@
     uint     cardid;
     InputMap inputs;
     DBChanList allchannels; ///< channels across all inputs
+
+    QWaitCondition  tuneCond;
+
+  private:
+    mutable ChannelThread   tuneThread;
+    Status   tuneStatus;
+    QMutex   thread_lock;
+    bool     abort_change;
 };
 
 #endif
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelchangemonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelchangemonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelchangemonitor.cpp	1969-12-31 18:00:00.000000000 -0600
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelchangemonitor.cpp	2009-12-27 01:41:46.000000000 -0600
@@ -0,0 +1,39 @@
+// -*- Mode: c++ -*-
+
+#include <cerrno>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "videodev_myth.h"
+#include "mythcontext.h"
+#include "channelchangemonitor.h"
+#include "v4lchannel.h"
+
+#define LOC QString("ChannelChangeM: ").arg(channel->GetDevice())
+#define LOC_ERR QString("ChannelChangeM, Error: ").arg(channel->GetDevice())
+
+ChannelChangeMonitor::ChannelChangeMonitor(
+    int db_cardnum, V4LChannel *_channel, uint64_t _flags) :
+    SignalMonitor(db_cardnum, _channel, _flags)
+{
+}
+
+void ChannelChangeMonitor::UpdateValues(void)
+{
+    if (!running || exit)
+        return;
+
+    if (!IsChannelTuned())
+        return;
+
+    {
+        QMutexLocker locker(&statusLock);
+        signalLock.SetValue(true);
+        signalStrength.SetValue(100);
+    }
+
+    EmitStatus();
+    SendMessageAllGood();
+}
+
+
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelchangemonitor.h mythtv-0.22.0-fixes23003/libs/libmythtv/channelchangemonitor.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelchangemonitor.h	1969-12-31 18:00:00.000000000 -0600
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelchangemonitor.h	2009-12-27 01:42:14.000000000 -0600
@@ -0,0 +1,23 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2005, Daniel Thor Kristjansson
+
+#ifndef _CHANNEL_CHANGE_MONITOR_H_
+#define _CHANNEL_CHANGE_MONITOR_H_
+
+// MythTV headers
+#include "signalmonitor.h"
+
+class V4LChannel;
+
+class ChannelChangeMonitor : public SignalMonitor
+{
+  public:
+    ChannelChangeMonitor(
+        int db_cardnum, V4LChannel *_channel,
+        uint64_t _flags = kSigMon_WaitForSig);
+
+    virtual void UpdateValues(void);
+};
+
+#endif // _CHANNEL_CHANGE_MONITOR_H_
+
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscan_sm.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscan_sm.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscan_sm.cpp	2009-10-29 03:37:46.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscan_sm.cpp	2009-12-27 01:43:02.000000000 -0600
@@ -1514,7 +1514,7 @@
     }
 
     // Start signal monitor for this channel
-    signalMonitor->Start();
+    signalMonitor->Start(false);
 
     timer.start();
     waitingForTables = true;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscan_sm.h mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscan_sm.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscan_sm.h	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscan_sm.h	2009-12-27 01:43:34.000000000 -0600
@@ -74,6 +74,7 @@
 
   public slots:
     virtual inline void AllGood(void);
+    virtual void StatusChannelTuned(const SignalMonitorValue&) { }
     virtual void StatusSignalLock(const SignalMonitorValue&) { }
     virtual void StatusSignalStrength(const SignalMonitorValue&) { }
 
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscanner_cli.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscanner_cli.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscanner_cli.cpp	2009-10-14 20:32:57.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscanner_cli.cpp	2009-12-27 01:44:11.000000000 -0600
@@ -92,6 +92,8 @@
             break;
         case ScannerEvent::SetStatusRotorPosition:
             break;
+        case ScannerEvent::SetStatusChannelTuned:
+            break;
         case ScannerEvent::SetStatusSignalLock:
             status_lock = scanEvent->intValue();
             break;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscanner_gui.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscanner_gui.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/channelscanner_gui.cpp	2009-10-14 20:32:57.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/channelscanner_gui.cpp	2009-12-27 01:44:39.000000000 -0600
@@ -156,6 +156,8 @@
         case ScannerEvent::SetStatusRotorPosition:
             scanStage->SetStatusRotorPosition(scanEvent->intValue());
             break;
+        case ScannerEvent::SetStatusChannelTuned:
+            break;
         case ScannerEvent::SetStatusSignalLock:
             scanStage->SetStatusLock(scanEvent->intValue());
             break;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/scanmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/scanmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/scanmonitor.cpp	2009-10-14 20:32:57.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/scanmonitor.cpp	2009-12-27 01:45:13.000000000 -0600
@@ -107,6 +107,11 @@
                val.GetNormalizedValue(0, 65535));
 }
 
+void ScanMonitor::StatusChannelTuned(const SignalMonitorValue &val)
+{
+    post_event(this, ScannerEvent::SetStatusChannelTuned, val.GetValue());
+}
+
 void ScanMonitor::StatusSignalLock(const SignalMonitorValue &val)
 {
     post_event(this, ScannerEvent::SetStatusSignalLock, val.GetValue());
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/scanmonitor.h mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/scanmonitor.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/channelscan/scanmonitor.h	2009-10-14 20:32:57.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/channelscan/scanmonitor.h	2009-12-27 01:45:55.000000000 -0600
@@ -64,6 +64,7 @@
 
     // SignalMonitorListener
     virtual void AllGood(void) { }
+    virtual void StatusChannelTuned(const SignalMonitorValue&);
     virtual void StatusSignalLock(const SignalMonitorValue&);
     virtual void StatusSignalStrength(const SignalMonitorValue&);
 
@@ -98,6 +99,7 @@
         SetStatusSignalToNoise,
         SetStatusSignalStrength,
         SetStatusSignalLock,
+        SetStatusChannelTuned
     };
 
     ScannerEvent(TYPE t) :
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/dtvsignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/dtvsignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/dtvsignalmonitor.cpp	2009-12-27 01:18:57.000000000 -0600
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/dtvsignalmonitor.cpp	2009-12-27 01:47:02.000000000 -0600
@@ -25,6 +25,7 @@
                                    uint64_t wait_for_mask)
     : SignalMonitor(db_cardnum, _channel, wait_for_mask),
       stream_data(NULL),
+      channelTuned(QObject::tr("Channel Tuned"), "tuned", 3, true, 0, 3, 0),
       seenPAT(QObject::tr("Seen")+" PAT", "seen_pat", 1, true, 0, 1, 0),
       seenPMT(QObject::tr("Seen")+" PMT", "seen_pmt", 1, true, 0, 1, 0),
       seenMGT(QObject::tr("Seen")+" MGT", "seen_mgt", 1, true, 0, 1, 0),
@@ -63,6 +64,13 @@
 {
     QStringList list = SignalMonitor::GetStatusList(kick);
     QMutexLocker locker(&statusLock);
+
+    // tuned?
+    if (flags & kSigMon_Tuned)
+    {
+        list<<channelTuned.GetName()<<channelTuned.GetStatus();
+    }
+
     // mpeg tables
     if (flags & kDTVSigMon_WaitForPAT)
     {
@@ -138,6 +146,7 @@
 void DTVSignalMonitor::UpdateMonitorValues(void)
 {
     QMutexLocker locker(&statusLock);
+    channelTuned.SetValue((flags & kSigMon_Tuned)      ? 3 : 1);
     seenPAT.SetValue(    (flags & kDTVSigMon_PATSeen)  ? 1 : 0);
     seenPMT.SetValue(    (flags & kDTVSigMon_PMTSeen)  ? 1 : 0);
     seenMGT.SetValue(    (flags & kDTVSigMon_MGTSeen)  ? 1 : 0);
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/dtvsignalmonitor.h mythtv-0.22.0-fixes23003/libs/libmythtv/dtvsignalmonitor.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/dtvsignalmonitor.h	2009-10-14 20:32:47.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/dtvsignalmonitor.h	2009-12-27 01:47:25.000000000 -0600
@@ -111,6 +111,7 @@
   protected:
     MPEGStreamData    *stream_data;
     vector<uint>       eit_pids;
+    SignalMonitorValue channelTuned;
     SignalMonitorValue seenPAT;
     SignalMonitorValue seenPMT;
     SignalMonitorValue seenMGT;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/dvbsignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/dvbsignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/dvbsignalmonitor.cpp	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/dvbsignalmonitor.cpp	2009-12-27 01:47:59.000000000 -0600
@@ -230,6 +230,9 @@
         return;
     }
 
+    if (!IsChannelTuned())
+        return;
+
     AddFlags(kSigMon_WaitForSig);
  
     DVBChannel *dvbchannel = GetDVBChannel();
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/firewiresignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/firewiresignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/firewiresignalmonitor.cpp	2009-10-14 20:32:46.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/firewiresignalmonitor.cpp	2009-12-27 01:48:24.000000000 -0600
@@ -190,6 +190,9 @@
     if (!running || exit)
         return;
 
+    if (!IsChannelTuned())
+        return;
+
     if (dtvMonitorRunning)
     {
         EmitStatus();
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/hdhrchannel.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/hdhrchannel.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/hdhrchannel.cpp	2009-10-14 20:32:46.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/hdhrchannel.cpp	2009-12-27 01:48:52.000000000 -0600
@@ -143,6 +143,9 @@
     if (!IsInputAvailable(currentInputID, mplexid_restriction))
         return false;
 
+    if (Aborted())
+       return false;
+
     // Fetch tuning data from the database.
     QString tvformat, modulation, freqtable, freqid, si_std;
     int finetune;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/hdhrsignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/hdhrsignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/hdhrsignalmonitor.cpp	2009-10-14 20:32:59.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/hdhrsignalmonitor.cpp	2009-12-27 01:49:16.000000000 -0600
@@ -105,6 +105,9 @@
         return;
     }
 
+    if (!IsChannelTuned())
+        return;
+
     struct hdhomerun_tuner_status_t status;
     streamHandler->GetTunerStatus(&status);
 
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/iptvsignalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/iptvsignalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/iptvsignalmonitor.cpp	2009-10-14 20:32:57.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/iptvsignalmonitor.cpp	2009-12-27 01:50:04.000000000 -0600
@@ -119,6 +119,9 @@
     if (!running || exit)
         return;
 
+    if (!IsChannelTuned())
+        return;
+
     if (dtvMonitorRunning)
     {
         EmitStatus();
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/libmythtv.pro mythtv-0.22.0-fixes23003/libs/libmythtv/libmythtv.pro
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/libmythtv.pro	2009-10-14 20:32:46.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/libmythtv.pro	2009-12-27 01:50:36.000000000 -0600
@@ -450,6 +450,9 @@
         LIBS += $$OSS_LIBS
     }
 
+    HEADERS += channelchangemonitor.h
+    SOURCES += channelchangemonitor.cpp
+
     # Support for Video4Linux devices
     using_v4l {
         HEADERS += v4lchannel.h                analogsignalmonitor.h
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitor.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitor.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitor.cpp	2009-10-14 20:32:58.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitor.cpp	2009-12-27 01:56:14.000000000 -0600
@@ -8,6 +8,7 @@
 
 // MythTV headers
 #include "mythcontext.h"
+#include "tv_rec.h"
 #include "signalmonitor.h"
 #include "compat.h"
 #include "mythverbose.h"
@@ -42,6 +43,8 @@
 #   include "firewirechannel.h"
 #endif
 
+#include "channelchangemonitor.h"
+
 #undef DBG_SM
 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
     "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
@@ -93,15 +96,16 @@
 #endif
 
 #ifdef USING_V4L
+#if 0 // Just use ChannelChangeMonitor for these types
     if ((cardtype.toUpper() == "V4L") ||
-        (cardtype.toUpper() == "MPEG") || 
-        (cardtype.toUpper() == "HDPVR"))
+        (cardtype.toUpper() == "MPEG"))
     {
         V4LChannel *chan = dynamic_cast<V4LChannel*>(channel);
         if (chan)
             signalMonitor = new AnalogSignalMonitor(db_cardnum, chan);
     }
 #endif
+#endif
 
 #ifdef USING_HDHOMERUN
     if (cardtype.toUpper() == "HDHOMERUN")
@@ -132,6 +136,13 @@
 
     if (!signalMonitor)
     {
+        V4LChannel *chan = dynamic_cast<V4LChannel*>(channel);
+        if (chan)
+            signalMonitor = new ChannelChangeMonitor(db_cardnum, chan);
+    }
+
+    if (!signalMonitor)
+    {
         VERBOSE(VB_IMPORTANT,
                 QString("Failed to create signal monitor in Init(%1, %2, 0x%3)")
                 .arg(cardtype).arg(db_cardnum).arg((long)channel,0,16));
@@ -160,11 +171,13 @@
       update_rate(25),                 minimum_update_rate(5),
       running(false),                  exit(false),
       update_done(false),              notify_frontend(true),
-      error(""),
+      is_tuned(false),                 tablemon(false),
+      eit_scan(false),                 error(""),
       signalLock    (QObject::tr("Signal Lock"),  "slock",
                      1, true, 0,   1, 0),
       signalStrength(QObject::tr("Signal Power"), "signal",
                      0, true, 0, 100, 0),
+      channelTuned("Channel Tuned", "tuned", 3, true, 0, 3, 0),
       statusLock(QMutex::Recursive)
 {
 }
@@ -202,11 +215,15 @@
 /** \fn SignalMonitor::Start()
  *  \brief Start signal monitoring thread.
  */
-void SignalMonitor::Start()
+void SignalMonitor::Start(bool waitfor_tune)
 {
     DBG_SM("Start", "begin");
     {
         QMutexLocker locker(&startStopLock);
+
+        // When used for scanning, don't wait for the tuning thread
+        is_tuned = !waitfor_tune;
+
         if (!running)
         {
             int rval = pthread_create(
@@ -279,6 +296,7 @@
 
     QStringList list;
     statusLock.lock();
+    list<<channelTuned.GetName()<<channelTuned.GetStatus();
     list<<signalLock.GetName()<<signalLock.GetStatus();
     if (HasFlags(kSigMon_WaitForSig))
         list<<signalStrength.GetName()<<signalStrength.GetStatus();
@@ -306,7 +324,6 @@
             QStringList slist = GetStatusList(false);
             MythEvent me(QString("SIGNAL %1").arg(capturecardnum), slist);
             gContext->dispatch(me);
-            //cerr<<"sent SIGNAL"<<endl;
         }
 
         usleep(update_rate * 1000);
@@ -441,6 +458,9 @@
         case kStatusSignalStrength:
             listener->StatusSignalStrength(val);
             break;
+        case kStatusChannelTuned:
+            listener->StatusChannelTuned(val);
+            break;
         case kStatusSignalToNoise:
             if (dvblistener)
                 dvblistener->StatusSignalToNoise(val);
@@ -461,6 +481,40 @@
     }
 }
 
+bool SignalMonitor::IsChannelTuned(void)
+{
+    if (is_tuned)
+        return true;
+
+    ChannelBase::Status status = channel->GetStatus();
+    QMutexLocker locker(&statusLock);
+
+    switch (status) {
+      case ChannelBase::changePending:
+        channelTuned.SetValue(1);
+        break;
+      case ChannelBase::changeFailed:
+        channelTuned.SetValue(2);
+        break;
+      case ChannelBase::changeSuccess:
+        channelTuned.SetValue(3);
+        break;
+    }
+
+    EmitStatus();
+
+    if (status == ChannelBase::changeSuccess)
+    {
+        if (tablemon)
+            pParent->SetupDTVSignalMonitor(eit_scan);
+
+        is_tuned = true;
+        return true;
+    }
+
+    return false;
+}
+
 void SignalMonitor::SendMessageAllGood(void)
 {
     QMutexLocker locker(&listenerLock);
@@ -470,6 +524,7 @@
 
 void SignalMonitor::EmitStatus(void)
 {
+    SendMessage(kStatusChannelTuned, channelTuned);
     SendMessage(kStatusSignalLock, signalLock);
     if (HasFlags(kSigMon_WaitForSig))
         SendMessage(kStatusSignalStrength,    signalStrength);
